package com.avengers.core.kit;

import com.avengers.core.bean.enums.HttpEnum;
import com.avengers.core.bean.enums.SymbolEnum;
import com.jfinal.kit.HttpKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author yu.wang
 * @since 2018-05-16 下午5:26
 */
public class IpKit {
    private static final int IP_DOT_COUNT = 3;

    public static String getRealIp() {
        // 本地IP，如果没有配置外网IP则返回它
        String localIp = null;
        // 外网IP
        String netIp = null;

        Enumeration<NetworkInterface> netInterfaces;
        try {
            netInterfaces = NetworkInterface.getNetworkInterfaces();
        } catch (SocketException e) {
            return null;
        }
        InetAddress ip;
        // 是否找到外网IP
        boolean found = false;
        while (netInterfaces.hasMoreElements() && !found) {
            NetworkInterface ni = netInterfaces.nextElement();
            Enumeration<InetAddress> address = ni.getInetAddresses();
            while (address.hasMoreElements()) {
                ip = address.nextElement();
                if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && !ip.getHostAddress().contains(":")) {
                    // 外网IP
                    netIp = ip.getHostAddress();
                    found = true;
                    break;
                } else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && !ip.getHostAddress().contains(":")) {
                    // 内网IP
                    localIp = ip.getHostAddress();
                }
            }
        }

        if (netIp != null && !netIp.isEmpty()) {
            return netIp;
        } else {
            return localIp;
        }
    }

    public static boolean isIp(String str) {
        return RegexKit.isIp(str);
    }

    public static boolean notIp(String str) {
        return !isIp(str);
    }

    public static String getIpConcat(String c, String line) {
        List<String> ipList = getIpList(line);
        if (ipList.isEmpty()) {
            return "";
        }
        return StringKit.concat(c, ipList.parallelStream().sorted().collect(Collectors.toList()));
    }

    public static String getIp(String line) {
        List<String> ipList = getIpList(line);
        if (ipList.isEmpty()) {
            return "";
        }
        return ipList.get(0);
    }

    public static List<String> getIpList(String line) {
        int ipDotCount = 0;
        char[] lineCharArray = line.toCharArray();
        List<String> ipList = new ArrayList<>();
        StringBuilder ipSb = new StringBuilder();
        for (int i = 0; i < lineCharArray.length; ) {
            char c = lineCharArray[i];

            if (c >= '0' && c <= '9') {
                for (int j = i; j < lineCharArray.length; i++, j++) {
                    char targetChar = lineCharArray[j];
                    boolean isNum = targetChar >= '0' && targetChar <= '9';
                    boolean isDot = targetChar == '.';
                    if (!isNum) {
                        if (ipDotCount == IP_DOT_COUNT) {
                            if (!ipList.contains(ipSb.toString())) {
                                ipList.add(ipSb.toString());
                            }
                            ipDotCount = 0;
                            ipSb.delete(0, ipSb.length());
                            break;
                        }
                        if (isDot) {
                            ipDotCount++;
                        } else {
                            ipDotCount = 0;
                            ipSb.delete(0, ipSb.length());
                            break;
                        }
                    }
                    ipSb.append(targetChar);
                }
            } else {
                i++;
            }
        }
        if (ipSb.length() > 0 && !ipList.contains(ipSb.toString())) {
            ipList.add(ipSb.toString());
        }
        return ipList;
    }

    private static final String ROUTE = "/ip";
    private static final String URL_MAIN = "www.17ex.com";
    private static final String URL_BACKUP = "103.10.84.212:58080";
    private static final String IP_CHECK_SIGN_NAME = "ip_check_17ex";
    private static final String IP_CHECK_TIMESTAMP = "time";
    private static final String IP_CHECK_KEY = "DA82D01BEE4EB522F05EEC8EDC140B17";

    private static final Logger log = LoggerFactory.getLogger(IpKit.class);

    public static String getExternalIp() {
        String ip = getExternalIp(URL_MAIN);
        if (StringKit.isBlank(ip) || notIp(ip)) {
            return getExternalIp(URL_BACKUP);
        }
        return StringKit.notBlank(ip) && isIp(ip) ? ip : null;
    }

    private static String getExternalIp(String host) {
        Map<String, String> headers = new HashMap<>();
        String timestamp = String.valueOf(System.currentTimeMillis());
        String sign = EncryptKit.sign("&timestamp=" + timestamp, IP_CHECK_KEY);
        headers.put(IP_CHECK_TIMESTAMP, timestamp);
        final String url;
        if (URL_MAIN.equals(host)) {
            url = HttpEnum.HTTPS.value + host + ROUTE + SymbolEnum.sprit + sign;
        } else {
            url = HttpEnum.HTTP.value + host + ROUTE;
            headers.put(IP_CHECK_SIGN_NAME, sign);
        }
        try {
            String ip = HttpKit.get(url, null, headers);
            log.info("get ip from {} result: {}", host, ip);
            return ip;
        } catch (Exception e) {
            log.error("get ip from {} with header: {} error:{}", host, headers, e.getMessage());
            return null;
        }
    }
}
